
#include <gfx/light.h>
#include <scene/ianimator.h>
#include <scene/node.h>
#include <scene/sector.h>

ceNode::ceNode ()
	: CE_ASSET_SUPER()
	, _parent (0)
  , _animator(0)
  , _clip (true)
	, _sector (0)
  , _inversionDirty (false)
{
  _localMatrix.SetIdentity();
  _localMatrixInverted.SetIdentity();
  _globalMatrix.SetIdentity();
  _globalMatrixInverted.SetIdentity();
  CE_OBJECT_CONSTR;
}

ceNode::~ceNode()
{
  CE_UNSET(_sector);
  CE_UNSET(_animator);

  for (unsigned i=0, ni=_children.size(); i<ni; ++i)
    {
      ceNode* child = _children[i];
      CE_UNSET(child);
    }

  _children.clear();
}

void ceNode::SetSector (ceSector* sector)
{
  CE_SET (_sector, sector);
}

ceSector* ceNode::GetSector () 
{
	return _sector;
}

const ceSector* ceNode::GetSector () const
{
	return _sector;
}


ceNode* ceNode::GetParent()
{
  return _parent;
}

const ceNode* ceNode::GetParent() const
{
  return _parent;
}

void ceNode::AddNode(ceNode *node)
{
  if (!node)
    {
      return;
    }

  // take the owner ship of the node
  node->AddRef();
  _children.push_back(node);

#if DEBUG
  if (node->_parent != 0)
    {
      printf ("Warning! Try to add a node to more than one node.")
    }
#endif
  node->_parent = this;
}

bool ceNode::RemoveNode(const ceNode *node, bool removeFromChildren)
{
  NodeVectorIterator it;
  for (it = _children.begin(); it != _children.end(); ++it)
    {
      ceNode* nd = *it;
      if (nd == node)
        {
          _children.erase(it);
          nd->Release();
          return true;
        }
    }
  if (removeFromChildren)
    {
      for (int i=_children.size()-1; i<=0; --i)
        {
          if (_children[i]->RemoveNode (node, true))
            {
              return true;
            }
        }
    }
  return false;
}


/* *******************************************
 *    Implementation of the transformation
 * *******************************************/

void ceNode::ClearTransformation()
{
  _localMatrix.SetIdentity();
  _inversionDirty = true;

}


void ceNode::SetMatrix(const ceMatrix4f &matrix)
{
  _localMatrix = matrix;
  _inversionDirty = true;
}

void ceNode::SetTranslation(const ceVector3f &translation)
{
  _localMatrix.SetTranslation(translation);
  _inversionDirty = true;
}


void ceNode::SetRotation(const ceVector3f &axis, float angle)
{
  _localMatrix.SetRotation(axis, angle);
  _inversionDirty = true;
}


void ceNode::Translate(const ceVector3f &translation)
{
  ceVector3f t = _localMatrix.Rotate(translation);
  _localMatrix.SetTranslation(_localMatrix.GetTranslation() + t);
  _inversionDirty = true;
}


void ceNode::Rotate(const ceVector3f &axis, float angle)
{
  ceMatrix4f r;
  r.SetRotation(axis, angle);
  _localMatrix = _localMatrix * r;
  _inversionDirty = true;
}

ceVector3f ceNode::GetTranslation() const
{
  return _localMatrix.GetTranslation();
}


ceVector3f ceNode::GetGlobalTranslation() const
{
  return _globalMatrix.GetTranslation();
}

void ceNode::GlobalLookAt(const ceVector3f &pos, const ceVector3f &up)
{

}


void ceNode::SetAnimator(iAnimator *animator)
{
  CE_SET(_animator, animator);
}

iAnimator* ceNode::GetAnimator()
{
  return _animator;
}

const iAnimator* ceNode::GetAnimator() const
{
  return _animator;
}


void ceNode::FinishTransformationPrivate()
{
  if (_parent)
    {
      _globalMatrix  = _parent->_globalMatrix * _localMatrix;
    }
  else
    {
      _globalMatrix = _localMatrix;
    }

  if (_inversionDirty)
    {
      _localMatrixInverted = _localMatrix.FastInverted();
      _globalMatrixInverted = _globalMatrix.FastInverted();
      _inversionDirty = false;
    }

  // if this is an entity or something else that has data attached, this should get propagated
  UpdateTransformation();

  for (int i=_children.size()-1; i>=0; --i)
    {
      ceNode* child = _children[i];
      child->FinishTransformationPrivate();
    }

  UpdateBoundingBox();

}



void ceNode::UpdateBoundingBox()
{
  _boundingBox.Clear();

  // add all the bounding boxes of all children
  for (int i=_children.size()-1; i>=0; --i)
    {
      ceNode* child = _children[i];
      _boundingBox.Add(child->GetBoundingBox());
    }

  // now add the private bounding box... if this is an entity or something else
  // the objects itself might have a bounding box
  FillPrivateBoundingBox(_boundingBox);
  _boundingBox.Update();
}

void ceNode::UpdateParentBoundingBox()
{
  UpdateBoundingBox();
  if (_parent)
    {
      _parent->UpdateParentBoundingBox();
    }
}

void ceNode::FinishTransformation(bool updateParent)
{
  FinishTransformationPrivate();
  if (updateParent && _parent)
    {
      _parent->UpdateParentBoundingBox();
    }
}


const ceBoundingBox& ceNode::GetBoundingBox() const
{
  return _boundingBox;
}

void ceNode::Update(ceRenderEnvironment &env, iDevice *device)
{
  if (_animator)
    {
      _animator->Animate(this, env);
    }
}


ceNodeType ceNode::GetNodeType() const
{
  return NT_Node;
}

void ceNode::SetClip(bool clip)
{
  _clip = clip;
}

bool ceNode::IsClip() const
{
  return _clip;
}


